#include <iostream>
#include <fstream>
#include <sstream>

#include "FileUtils.hpp"

namespace FileUtils
{

void openBinaryFile(const std::string& filename, vuc_t& filebuffer)
{

    if(filename.empty())
    {
        return;
    }

    std::ifstream filedata(filename.c_str(), std::ios::in | std::ios::binary | std::ios::ate);

    if(filedata.is_open())
    {
        std::ifstream::pos_type filesize = filedata.tellg();

        char* data = new char[filesize];
        filedata.seekg (0, std::ios::beg);
        filedata.read(data, filesize);
        filedata.close();

        for(int i=0; i<filesize; ++i)
        {
            filebuffer.push_back(data[i]);
        }

    }
    else
    {
        std::cout<<"Unable to open file: "<<filename<<std::endl;
    }
}

ui_t stringToInteger(const str_t& pString)
{
    std::stringstream ss;
    ss<<pString;
    int integer;
    ss>>integer;
    return integer;
}

bool checkPPMFileHeader(ui_t& width, ui_t& height, vuc_t& data, vuc_t& imagedata)
{
    if(0 == data.size())
    {
        return false;
    }
    //get dimensions from file
    str_t psixheader ="";
    psixheader += data[0];
    psixheader += data[1];
    vuc_t::iterator dataiter;
    if(0 == psixheader.compare("P6"))
    {
        dataiter = data.begin();
        ++dataiter;
        ++dataiter;
        ++dataiter;
        if('#' == *dataiter)
        {
            for(; dataiter!=data.end(); ++dataiter)
            {
                if('\n' == *dataiter)
                {
                    ++dataiter;
                    break;
                }
            }
        }
        str_t widthstr = "";
        str_t heightstr = "";
        str_t line = "";
        for(; dataiter!=data.end(); ++dataiter)
        {
            line += *dataiter;
            if(' ' == *dataiter)
            {
                widthstr = line;
                line="";
            }
            if('\n' == *dataiter)
            {
                heightstr = line;
                line="";
                ++dataiter;
                break;
            }
        }
        width = stringToInteger(widthstr);
        height = stringToInteger(heightstr);

        //maximum color channel value
        for(; dataiter!=data.end(); ++dataiter)
        {
            if('\n' == *dataiter)
            {
                ++dataiter;
                break;
            }
        }

        for(; dataiter!=data.end(); ++dataiter)
        {
            imagedata.push_back(*dataiter);
        }

        return true;
    }
    return false;
}

void writeBinaryFile(const str_t& pFilename, vuc_t& pData)
{
    std::ofstream filedata(pFilename.c_str(), std::ios::out | std::ios::binary | std::ios::app);

    if(filedata.is_open())
    {
        vuc_t::const_iterator dataiter;
        long datasize = 1;
        for(dataiter=pData.begin(); dataiter!=pData.end(); ++dataiter)
        {
            char databyte = *dataiter;
            filedata.write(&databyte, datasize);
        }
        filedata.close();

    }
}

void stringToUnsignedCharVector(const str_t& pInput, vuc_t& pOutput)
{
    str_t::const_iterator inputiter;
    for(inputiter = pInput.begin(); inputiter != pInput.end(); ++inputiter)
    {
        pOutput.push_back(*inputiter);
    }
}

bool openPPMFile(const str_t& pFilename, ui_t& pWidth, ui_t& pHeight, vuc_t& pImageData)
{
    vuc_t ppmdata;
    FileUtils::openBinaryFile(pFilename, ppmdata);
    if( FileUtils::checkPPMFileHeader(pWidth, pHeight, ppmdata, pImageData) )
    {
        return true;
    }
    else
    {
        return false;
    }
    return false;
}

}
